import xtriui
import uix
import uiutil
import mathUtil
import uthread
import util
import blue
import uicls
import uiconst

class Slider(uicls.Container):
    __guid__ = 'xtriui.Slider'
    __nonpersistvars__ = ['value',
     'dragging',
     'offset',
     'minValue',
     'maxValue',
     'config',
     'interested',
     'sliderID',
     'label',
     'displayName',
     'SetSliderLabel',
     'valueproportion']

    def init(self):
        self.value = None
        self.valueproportion = None
        self.increments = []
        self.label = None
        self.top = 0



    def _OnClose(self):
        uicls.Container._OnClose(self)
        self.EndSetSliderValue = None
        self.GetSliderValue = None
        self.SetSliderLabel = None



    def Startup(self, sliderID, minValue, maxValue, config = None, displayName = None, increments = None, usePrefs = 0, startVal = None):
        self.sliderID = sliderID
        self.minValue = minValue
        self.maxValue = maxValue
        self.config = config
        self.usePrefs = usePrefs
        for each in self.parent.children[:]:
            if (each.name == 'label'):
                self.label = each

        if displayName:
            self.displayName = displayName
        if increments:
            self.SetIncrements(increments)
        if config:
            if (len(config) == 3):
                (cfgName, prefsType, defaultValue,) = config
                if prefsType:
                    rec = util.GetAttrs(settings, *prefsType)
                    if (rec is not None):
                        value = rec.Get(cfgName, defaultValue)
                    else:
                        value = defaultValue
                else:
                    value = defaultValue
                self.name = config[0]
            elif usePrefs:
                value = prefs.GetValue(config, ((maxValue - minValue) * 0.5))
            else:
                value = settings.user.ui.Get(config, ((maxValue - minValue) * 0.5))
            if (value is None):
                value = 0.0
            else:
                value = max(minValue, min(maxValue, value))
            self.name = config
            nval = ((float(value) - self.minValue) / (self.maxValue - self.minValue))
            self.SlideTo(nval, 1)
            self.SetValue(nval)
        elif (startVal is not None):
            self.SlideTo(startVal, 1)
            self.SetValue(startVal)
        else:
            self.state = uix.UI_NORMAL



    def SetIncrements(self, increments, draw = 1):
        if (len(increments) < 3):
            return 
        self.increments = [[], []]
        for inc in increments:
            self.increments[0].append(inc)
            self.increments[1].append(((inc - self.minValue) / float((self.maxValue - self.minValue))))

        if draw:
            self.DrawIncrement()



    def DrawIncrement(self):
        if self.increments:
            uiutil.Update(self, 'Slider::DrawIncrement')
            (l, t, w, h,) = self.parent.GetAbsolute()
            maxX = (w - self.width)
            uicls.Line(parent=self.parent, align=uiconst.TOPLEFT, height=2, width=(maxX - 1), left=(self.width / 2), top=(self.height + 2))
            i = 0
            for each in self.increments[1]:
                height = 5
                if (i in (0, (len(self.increments[1]) - 1))):
                    height = 10
                uicls.Line(parent=self.parent, align=uiconst.TOPLEFT, height=height, width=1, left=((int((each * maxX)) + (self.width / 2)) - 1), top=(self.height - 6))
                i += 1




    def SetHandle(self, bluefile, width = None, height = None):
        uix.Flush(self)
        bluefile.state = uix.UI_DISABLED
        bluefile.left = bluefile.top = bluefile.width = bluefile.height = 0
        bluefile.align = uix.UI_ALCLIENT
        self.children.append(bluefile)
        if width:
            self.width = width
        if height:
            self.height = height



    def SetUnderlay(self, bluefile, left = 0, top = 0):
        uix.FlushList(self.parent.children[1:])
        bluefile.state = uix.UI_DISABLED
        bluefile.left = bluefile.width = left
        bluefile.top = bluefile.height = top
        bluefile.align = uix.UI_ALCLIENT
        self.parent.children.append(bluefile)



    def SetLabel(self, label, leftright = 'left'):
        uicls.Label(text=('<%s>%s' % (leftright, label)), parent=self.parent, left=4, top=-4, width=self.parent.width, autowidth=False, letterspace=2, fontsize=9, state=uiconst.UI_DISABLED)



    def GetValue(self):
        return self.value



    def MorphTo(self, value, time = 150.0):
        if (getattr(self, 'morphTo', None) is not None):
            self.pendingMorph = (value, time)
            return 
        self.morphTo = value
        startPos = (self.value / (self.maxValue - self.minValue))
        endPos = (value / (self.maxValue - self.minValue))
        (start, ndt,) = (blue.os.GetTime(), 0.0)
        while (ndt != 1.0):
            ndt = min((blue.os.TimeDiffInMs(start) / time), 1.0)
            newVal = mathUtil.Lerp(startPos, endPos, ndt)
            self.SlideTo(newVal)
            self.SetValue(newVal)
            blue.pyos.synchro.Yield()

        self.morphTo = None
        if getattr(self, 'pendingMorph', None):
            (value, time,) = self.pendingMorph
            self.MorphTo(value, time)
        self.pendingMorph = None



    def SlideTo(self, value, update = 1):
        if update:
            uiutil.Update(self, 'Slider::SlideTo')
        (l, t, w, h,) = self.parent.GetAbsolute()
        maxX = (w - self.width)
        left = max(0, int((maxX * value)))
        if self.increments:
            steps = [ int((incproportion * maxX)) for incproportion in self.increments[1] ]
            left = self.FindClosest(left, steps)
        self.left = int(left)
        self.state = uix.UI_NORMAL



    def SetValue(self, value):
        if self.increments:
            value = self.FindClosest(self.RoundValue(value), self.increments[1])
        value = max(0.0, min(1.0, value))
        nval = (self.minValue + ((-self.minValue + self.maxValue) * value))
        self.value = nval
        self.valueproportion = value
        self.GetSliderValue(self.sliderID, self.GetValue())
        self.UpdateLabel()
        self.OnSetValue(self)



    def RoundValue(self, value):
        return float(('%.2f' % value))



    def FindClosest(self, check, values):
        mindiff = (self.maxValue - self.minValue)
        found = (self.maxValue - self.minValue)
        for value in values:
            diff = abs((value - check))
            if (diff < mindiff):
                mindiff = diff
                found = value

        return found



    def UpdateLabel(self):
        if self.label:
            if getattr(self, 'SetSliderLabel', None):
                self.SetSliderLabel(self.label, self.sliderID, self.displayName, self.GetValue())
            elif self.displayName:
                self.label.text = ('%s %.2f' % (self.displayName, self.GetValue()))
            else:
                self.label.text = ('%.2f' % self.GetValue())



    def _OnMouseDown(self, *blah):
        offset = (eve.triapp.uilib.x - self.absoluteLeft)
        self.offset = offset
        self.dragging = 1



    def _OnMouseUp(self, *blah):
        eve.triapp.uilib.UnclipCursor()
        self.dragging = 0
        if self.config:
            if (len(self.config) == 3):
                (cfgName, prefsType, defaultValue,) = self.config
                if prefsType:
                    rec = util.GetAttrs(settings, *prefsType)
                    if (rec is not None):
                        value = rec.Set(cfgName, self.value)
            if self.usePrefs:
                prefs.SetValue(self.config, self.value)
            else:
                settings.user.ui.Set(self.config, self.value)
        if hasattr(self, 'EndSetSliderValue'):
            self.EndSetSliderValue(self)



    def _OnMouseMove(self, *blah):
        if self.dragging:
            screenLoc = (eve.triapp.uilib.x - self.offset)
            localX = max(0, (screenLoc - self.parent.absoluteLeft))
            maxX = ((self.parent.absoluteRight - self.parent.absoluteLeft) - self.width)
            localX = min(maxX, localX)
            if self.increments:
                steps = [ int((incproportion * maxX)) for incproportion in self.increments[1] ]
                localX = self.FindClosest(localX, steps)
            if (self.left == localX):
                return 
            self.left = localX
            self.SetValue((localX / float(maxX)))



    def GetSliderValue(self, *args):
        return 



    def OnSetValue(self, *args):
        return 




